

#ifndef OTA_PB_H__
#define OTA_PB_H__

#include <stdint.h>
#include <stdbool.h>
#include "xota+crypto+types.h" 
//#include "app_util_platform.h"
#include "app_util.h"

#include "pb.def.h"

#define OTA_PB_VERSION		0x01030100

typedef enum{
	PB_INIT_SIGN = 1, 

	PB_INIT_HASH, 
	PB_INIT_CRC32, 
	PB_INIT_OTA_TYPE, 
	PB_INIT_APP_SIZE, 
	PB_INIT_SD_SIZE, 
	PB_INIT_BL_SIZE, 
	PB_INIT_FW_VER, 
	PB_INIT_HW_VER, 
	PB_INIT_SD_FWID, 	
	PB_INIT_APP_FWID, 
}PB_INIT_TYPE; 

typedef enum{
    OTA_EPB_SUCCESS = 0, 
    
    OTA_EPB_ERR_INVALID_LENGTH,	// 1
	OTA_EPB_ERR_INVALID_FORMAT, // 2
    
	OTA_EPB_ERR_DATA_SIZE_ERROR , // 3
	OTA_EPB_ERR_RESOURCE_INSUFFICIENT, // 4  
	OTA_EPB_ERR_SUB_FUNCTION_NOT_SUPPORTED , // 5  
	OTA_EPB_ERR_NO_MEM,     // 6
	OTA_EPB_ERR_ADDR_RESP,  // 7 
	OTA_EPB_ERR_INVALID_KEY, //8 
	OTA_EPB_ERR_DELAY_NOT_EXPIRED_TIME, // 9   
	OTA_EPB_ERR_INVALID_STATE, // 10
	OTA_EPB_ERR_INVALID_PARAMS, // 11
	OTA_EPB_ERR_BUSY, // 12 
	OTA_EPB_ERR_INVALID_ADDR, // 13 
	OTA_EPB_ERR_NULL,  //14 
	OTA_EPB_ERR_INVALID_OBJECT, //15
	OTA_EPB_ERR_OPERATE_CODE_NOT_PERMITTED, //16
	OTA_EPB_ERR_VERSION_TOO_LOW, //17
	OTA_EPB_ERR_SIGNATURE_TYPE_NOT_SUPPORTED, //18
	OTA_EPB_ERR_SIGNATURE_VERIFY_FAIL, //19 
	OTA_EPB_ERR_HASH_NOT_FOUND, // 20
	OTA_EPB_ERR_APP_SIZE, // 21
	OTA_EPB_ERR_FIND_HASH_FAIL, // 22
	OTA_EPB_ERR_FIRMWARE_HASH, // 23
	OTA_EPB_ERR_FIMRWARE_CRC, //24 
	OTA_EPB_ERR_POWER_LOW,  //25 
	OTA_EPB_ERR_TIMEOUT, //26 
	OTA_EPB_ERR_HASH_TYPE_NOT_SUPPORTED, //27
	OTA_EPB_ERR_FIRMWARE_TYPE_NOT_SUPPORTED, //28 
	OTA_EPB_ERR_PROG_ERROR, 
    
	OTA_EPB_ERR_UNKNOWN= 0xff, 
}ota_pb_err_code_t; 

#pragma push 
#pragma anon_unions


typedef enum{
//	OTA_OPCODE_NONE 		= 0,	// No operation set  
	OTA_OPCODE_INIT			= 0x01,	// Create Initial Command 
	OTA_OPCODE_WRITE		= 0x02,	// Write Firmware Content 
	OTA_OPCODE_EXECUTE 		= 0x03, 	// Execute Firmware 
	
	OTA_OPCODE_QUERY		= 0x0C, // Query Bootloader State 
	OTA_OPCODE_RESET 		= 0x0D,	// Force Device Reset 
	OTA_OPCODE_MTU			= 0x0E, // Query Max Length Support 
	OTA_OPCODE_VERSION 		= 0x0F,
}ota_pb_req_op_type_t; 

typedef enum{
	OTA_RES_TYPE_NO_RESP = 0, 	// No Response 
	OTA_RES_TYPE_POS_RESP = 1, 
	OTA_RES_TYPE_ERROR_CODE = 2, 
}ota_pb_res_type_t; 


typedef enum
{
    OTA_FW_TYPE_APPLICATION = 0,
    OTA_FW_TYPE_SOFTDEVICE = 1,
    OTA_FW_TYPE_BOOTLOADER = 2,
    OTA_FW_TYPE_SOFTDEVICE_BOOTLOADER = 3
} ota_pb_fw_type_t;
#define OTA_FW_TYPE_MIN OTA_FW_TYPE_APPLICATION
#define OTA_FW_TYPE_MAX OTA_FW_TYPE_SOFTDEVICE_BOOTLOADER
#define OTA_FW_TYPE_ARRAYSIZE ((ota_fw_type_t)(OTA_FW_TYPE_SOFTDEVICE_BOOTLOADER+1))

typedef enum
{
    OTA_HASH_TYPE_NO_HASH = 0,
    OTA_HASH_TYPE_SHA256 = 1,
    OTA_HASH_TYPE_MD5 = 2, 
	OTA_HASH_TYPE_LAST, 
} ota_hash_type_t;
#define OTA_HASH_TYPE_MIN OTA_HASH_TYPE_NO_HASH
#define OTA_HASH_TYPE_MAX OTA_HASH_TYPE_MD5
#define OTA_HASH_TYPE_ARRAYSIZE ((ota_hash_type_t)(OTA_HASH_TYPE_LAST))

typedef enum
{
    OTA_SIGNATURE_TYPE_ECDSA_P256_SHA256 = 0,
	OTA_SIGNATURE_TYPE_ED25519 = 1, 
} ota_pb_signature_type_t;
#define OTA_SIGNATURE_TYPE_MIN OTA_SIGNATURE_TYPE_ECDSA_P256_SHA256
#define OTA_SIGNATURE_TYPE_MAX OTA_SIGNATURE_TYPE_ED25519
#define OTA_SIGNATURE_TYPE_ARRAYSIZE ((ota_signature_type_t)(OTA_SIGNATURE_TYPE_ED25519+1))


/* Struct definitions */
//typedef PB_BYTES_ARRAY_T(32) ota_hash_hash_t;
typedef struct{
	uint8_t 	size; 
	uint8_t 	bytes[32]; 
}ota_hash_hash_t; 

typedef struct {
    ota_hash_type_t hash_type;
    ota_hash_hash_t hash;
/* @@protoc_insertion_point(struct:ota_hash_t) */
} ota_hash_t;

typedef struct{
	bool has_app_fwid;
	uint32_t app_fwid; 
	
	bool has_fw_version;
	uint32_t fw_version; 
	bool has_hw_version; 
	uint32_t hw_version; 
//	uint8_t sd_req_count; 
//	uint32_t sd_req[16]; 
	bool has_type; 
	ota_pb_fw_type_t type;
	
	bool has_sd_size; 
	uint32_t sd_size; 
	bool has_bl_size; 
	uint32_t bl_size; 
	bool has_app_size; 
	uint32_t app_size; 
	
	bool has_hash; 
	ota_hash_t	hash; 	
	bool has_crc; 
	uint32_t 	crc32; 
	
	uint32_t command_start;
	uint32_t command_size; 
	
	bool has_is_debug;
	bool is_debug;
	
	
}ota_pb_init_command_t; 


typedef struct{
	bool has_init;
	ota_pb_init_command_t init;
}ota_pb_command_t;

typedef struct{
	uint8_t 	size; 
	uint8_t 	bytes[64]; 
}ota_pb_signed_command_signature_t;

typedef struct{	
//	bool has_command;
//	ota_pb_command_t command;
	
	ota_pb_signature_type_t signature_type; 
	ota_pb_signed_command_signature_t signature;
}ota_pb_signed_command_t; 


typedef struct{
	bool has_command;
	ota_pb_command_t command;
	
	bool has_signed_command;
	ota_pb_signed_command_t signed_command;	
}ota_pb_packet_t;

typedef struct{
	uint32_t 	offset; 
	uint16_t 	size; 
	uint8_t* 	p_data; 	
}ota_pb_write_command_t; 

typedef struct{
	ota_pb_req_op_type_t	req_type; 
	bool 					has_crypto; 
	uint8_t 				crypto_type; 
	
	union{
		struct{
			uint8_t*		p_req;
			uint16_t 		req_len;
		};
	};
}ota_pb_req_t; 

typedef struct{
	ota_pb_res_type_t		res_type; 
	uint8_t 				res_len; 
	uint8_t 				res_array[12]; // do not exceed 12bytes 
}ota_pb_resp_t; 


#define OTA_PB_PACKET_DEF	\
{\
	.has_command = false, \
	.command.init.has_is_debug = false,\
	.command.init.is_debug = false, \
	.has_signed_command = false,\
}

//typedef void (*ota_pb_consume_t)( ota_pb_req_t* p_req, ota_pb_resp_t *  ota_pb_resp_t);


//typedef struct{
//	ota_pb_consume_t 		data_handle; 
//}ota_pb_init_t;

//typedef struct{
//	ota_pb_consume_t 		data_handle;
//	pb_tx_data_handle_t  	callback; 
//}ota_pb_t;

#pragma pop


#define PB_SIGNED_COMMAND_SIZE		(40)	//32hash + 4type 
#define PB_CREATE_COMMAND_SIZE		(160)	//
#define PB_WRITE_COMMAND_MIN_SIZE	(4 + 4 ) 
#define PB_WRITE_COMMAND_SIZE		(256 + 8)//offset + fw 

#define PB_COMMAND_MAX_SIZE			 PB_WRITE_COMMAND_SIZE


//uint32_t ota_pb_init_decode( 	uint8_t * p_data, 
//								uint16_t len, 
//								pb_create_command_t * p_init, 
//								ota_value_length_t * ota_init_value
//								);

uint32_t xota_pb_deocde_init_cmd(pb_stream_t * p_stream, ota_pb_packet_t* p_ota_pb_packet);

uint32_t xota_pb_decode_write_cmd( pb_stream_t * p_stream,ota_pb_write_command_t * p_ota_pb_write); 

//void ota_pb_init(ota_pb_init_t* p_pb_init_obj);


#endif 

